#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "init.h"
#include "tool.h"
#include "valloc.h"
#include "sort.h"
#include "list.h"

static void test_basic_usage(void)
{
    /* 针对int型数组，进行升序 
     */
    int array_int[] = {1, 3, 6, 5, 0, 2, 9, 8, 7, -4}; // 定义时候任意乱序

    // 传入数组基地址，排序的区间，指定int型的升序ops
    sort_bubble(array_int, 0, sizeof(array_int)/sizeof(array_int[0]) - 1, &sops_int_ascend);

    // 输出排序后的数组
    for (int i = 0; i < sizeof(array_int)/sizeof(array_int[0]); i++)
    {
        printf("%d, ", array_int[i]);
    }
    printf("\r\n");

    /* ---------------------------------------- 代码分割线 ----------------------------------------  */

    /* 针对float型数组，进行降序 
     */
    float array_float[] = {-1.1, 2.1, 6.6, 5.0, 0.1, 2.8, 9.9, 9.8, 7.0, -4.5}; // 定义时候任意乱序

    // 传入数组基地址，排序的区间，指定float型的降序ops
    sort_bubble(array_float, 0, sizeof(array_float)/sizeof(array_float[0]) - 1, &sops_float_descend);

    // 输出排序后的数组
    for (int i = 0; i < sizeof(array_float)/sizeof(array_float[0]); i++)
    {
        printf("%.2f, ", array_float[i]);
    }
    printf("\r\n");
}

static void test_interval(void)
{
    int array_int[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; // 先定义升序的数组

    // 传入数组基地址，指定在[3, 7]区间内进行排序，指定int型的降序ops
    sort_bubble(array_int, 3, 7, &sops_int_descend);

    // 输出排序后的数组
    for (int i = 0; i < sizeof(array_int)/sizeof(array_int[0]); i++)
    {
        printf("%d, ", array_int[i]);
    }
    printf("\r\n");
}

// 获取list数据项地址
static void* list_int_addr(void *array, int index)
{
    return list_data((list_t)array, index);
}

// 交换list两个成员数据
static void list_int_swap(void *array, int index0, int index1)
{
    int temp = list_at((list_t)array, int, index0);
    list_at((list_t)array, int, index0) = list_at((list_t)array, int, index1);
    list_at((list_t)array, int, index1) = temp;
}

// 显示list存储的数据
static void list_int_show(list_t list)
{
    for (int i = 0; i < list_size(list); i++)
    {
        printf("%d, ", list_at(list, int, i));
    }
    printf("\r\n");
}

static void test_list_sort(void)
{
    list_t list = list(int);     // 定义一个int型的list
    SOPS ops;                    // 定义一个新的ops
    int array[] = {1, 3, 6, 5, 0, 2, 9, 8, 7, -4}; // 定义要给list装载的数据

    // 将数据装载到list
    for (int i = 0; i < sizeof(array)/sizeof(array[0]); i++)
    {
        list_push_back(list, &array[i]);
    }

    ops.order = sops_int_ascend.order; // 复用int升序规则
    ops.addr = list_int_addr; // 使用list获取元素的地址
    ops.swap = list_int_swap; // list交换数据

    // 输出排序前的list
    list_int_show(list);

    // 进行排序
    sort_bubble(list, 0, list_size(list) - 1, &ops);

    // 输出排序后的list
    list_int_show(list);

    // 释放list
    _list(list);
}

typedef struct 
{
    char *name;
    int age;
    char gender; /* 1 表示男，0 表示女 */
    float weight;
} STUDENT;

static void student_print(STUDENT *s, int size)
{
    for (int i = 0; i < size; i++)
    {
        printf("name: %s, \t\t age = %d, \t\t gender = %d, \t\t weight = %.2f\r\n", s[i].name, s[i].age, s[i].gender, s[i].weight);
    }
}

static void* student_addr(void *array, int index)
{
    return ((STUDENT *)array) + index;
}

static void student_swap(void *array, int index0, int index1)
{
    STUDENT temp = ((STUDENT *)array)[index0];
    ((STUDENT *)array)[index0] = ((STUDENT *)array)[index1];
    ((STUDENT *)array)[index1] = temp;
}

static int student_name_ascend(void *front, void *back)
{
    return -strcmp(((STUDENT *)front)->name, ((STUDENT *)back)->name);
}

static int student_gender_descend(void *front, void *back)
{
    if (((STUDENT *)front)->gender > ((STUDENT *)back)->gender) return 1;
    else if (((STUDENT *)front)->gender < ((STUDENT *)back)->gender) return -1;
    else return 0;
}

static int student_age_descend(void *front, void *back)
{
    if (((STUDENT *)front)->age > ((STUDENT *)back)->age) return 1;
    else if (((STUDENT *)front)->age < ((STUDENT *)back)->age) return -1;
    else return 0;
}

static int student_weight_ascend(void *front, void *back)
{
    if (((STUDENT *)front)->weight < ((STUDENT *)back)->weight) return 1;
    else if (((STUDENT *)front)->weight > ((STUDENT *)back)->weight) return -1;
    else return 0;
}

static void test_struct(void)
{
    SOPS ops;
    STUDENT table[] = {
        {"ZhanSan",    18,        1,        56.3},
        {"LiSi",    17,        1,        62.2},
        {"WangWu",    21,        0,        58.9},
        {"ZhaoLiu",    22,        1,        65.5},
        {"SunQi",    18,        1,        71.7},
        {"ZhouBa",    30,        0,        48.8},
        {"WuJiu",    16,        1,        56.3},
        {"ZhenShi",    19,        0,        52.1},
    };

    ops.addr = student_addr;
    ops.swap = student_swap;

    // 指定为按照名字升序排序
    ops.order = student_name_ascend;
    sort_bubble(table, 0, sizeof(table)/sizeof(table[0])-1, &ops);
    printf("sorting by name in ascending order\r\n");
    student_print(table, sizeof(table)/sizeof(table[0]));
    printf("---------------------------------\r\n");

    // 指定为按照年龄降序排序
    ops.order = student_age_descend;
    sort_bubble(table, 0, sizeof(table)/sizeof(table[0])-1, &ops);
    printf("sorting by age in descending order\r\n");
    student_print(table, sizeof(table)/sizeof(table[0]));
    printf("---------------------------------\r\n");

    // 指定为按照性别降序排序
    ops.order = student_gender_descend;
    sort_bubble(table, 0, sizeof(table)/sizeof(table[0])-1, &ops);
    printf("sorting by gender in descending order\r\n");
    student_print(table, sizeof(table)/sizeof(table[0]));
    printf("---------------------------------\r\n");

    // 指定为按照体重升序排序
    ops.order = student_weight_ascend;
    sort_bubble(table, 0, sizeof(table)/sizeof(table[0])-1, &ops);
    printf("sorting by weight in ascending order\r\n");
    student_print(table, sizeof(table)/sizeof(table[0]));
    printf("---------------------------------\r\n");
}

static void test(void)
{
    // test_basic_usage();
    // test_interval();
    // test_list_sort();
    test_struct();
}

init_export_app(test);
